
#include "hal_adc.h"

void ADC_HAL_ConfigConverter(ADC_Type *base, ADC_ConverterConfig_T *config)
{
    /* ADCx_CFG1. */
    base->CFG1 = ADC_CFG1_ADICLK(config->ClockSource) /* ADC转换器时钟源 */
               | ADC_CFG1_ADIV(config->ClockDivider)  /* ADC转换器时钟源分频因子 */
               | ADC_CFG1_MODE(config->ResolutionBits); /* 转换分辨率 */

    /* ADCx_CFG2. */
    base->CFG2 = ADC_CFG2_SMPLTS(config->SampleClockCount - 1U); /* 采样保持时间 */

    /* ADCx_SC2. */
    base->SC2 = (base->SC2 & ~ADC_SC2_REFSEL_MASK)
              | ADC_SC2_REFSEL(config->RefVoltSource);
}

void ADC_HAL_DoAutoCalibration(ADC_Type *base)
{
    /* Before starting calibration, the calibration registers (CLPS, CLP3, CLP2, CLP1,
       CLP0, CLPX, and CLP9) must be cleared by writing 0x0 into them. */
    base->CLPS = 0U;
    base->CLP3 = 0U;
    base->CLP2 = 0U;
    base->CLP1 = 0U;
    base->CLP0 = 0U;
    base->CLPX = 0U;
    base->CLP9 = 0U;
    /* Trigger calibration and wait until it complete. */
    base->SC3 |= ADC_SC3_CAL_MASK;
    while (ADC_SC1_COCO_MASK != (ADC_SC1_COCO_MASK & base->SC1[0]))
    {
    }
    ADC_HAL_GetChannelConvValue(base, 0U); /* Dummy read to claer the COCO flag. */
}

void ADC_HAL_SetConvTriggerMode(ADC_Type *base, ADC_ConvTrigger_T trigger)
{
    switch (trigger)
    {
        case eADC_ConvTriggerByHardware:
            base->SC2 |= ADC_SC2_ADTRG_MASK;
            break;
        default: /* eADC_ConvTriggerBySoftware */
            base->SC2 &= ~ADC_SC2_ADTRG_MASK;
            break;
    }
}


void ADC_HAL_SetHardwareCompareMode(ADC_Type *base, ADC_HardwareCompareConfig_T *config)
{
    uint32_t tmp32;

    /* Disable hardware compare. */
    if (NULL == config)
    {
        base->SC2 &= ~(ADC_SC2_ACFE_MASK | ADC_SC2_ACFGT_MASK | ADC_SC2_ACREN_MASK);
    }
    else
    {
        /* Set the compare mode. */
        tmp32 = (base->SC2 & ~(ADC_SC2_ACFE_MASK | ADC_SC2_ACFGT_MASK | ADC_SC2_ACREN_MASK));
        switch (config->HardwareCompareMode)
        {
            case eADC_HardwareCompareMode0:
                break;
            case eADC_HardwareCompareMode1:
                tmp32 |= ADC_SC2_ACFGT_MASK;
                break;
            case eADC_HardwareCompareMode2:
                tmp32 |= ADC_SC2_ACREN_MASK;
                break;
            case eADC_HardwareCompareMode3:
                tmp32 |= (ADC_SC2_ACFGT_MASK | ADC_SC2_ACREN_MASK);
                break;
            default: /*  */
                break;
        }
        tmp32 |= ADC_SC2_ACFE_MASK; /* 启用硬件比较功能 */
        base->SC2 = tmp32;

        /* Set the compare value. */
        base->CV1 = config->Value1;
        base->CV2 = config->Value2;
    }
}

void ADC_HAL_SetHardwareAverageMode(ADC_Type *base, ADC_HardwareAverageMode_T mode)
{
    /* ADCx_SC3. */
    if (eADC_HardwareAverageDisabled == mode)
    {
        base->SC3 &= ~(ADC_SC3_AVGS_MASK | ADC_SC3_AVGE_MASK);
    }
    else
    {
        base->SC3 |= (ADC_SC3_AVGS(mode) | ADC_SC3_AVGE_MASK);
    }
}

void ADC_HAL_EnableDMAOnChannelConvDone(ADC_Type *base, bool enable)
{
    if (enable)
    {
        base->SC2 |= ADC_SC2_DMAEN_MASK;
    }
    else
    {
        base->SC2 &= ~ADC_SC2_DMAEN_MASK;
    }
}

void ADC_HAL_EnableContinuousConvMode(ADC_Type *base, bool enable)
{
    /* ADCx_SC3. */
    if (enable)
    {
        base->SC3 |= ADC_SC3_ADCO_MASK;
    }
    else
    {
        base->SC3 &= ~ADC_SC3_ADCO_MASK;
    }
}

void ADC_HAL_SetChannelConvCmd(ADC_Type *base, uint32_t channelGroup, ADC_ConvCommand_T *cmd)
{
    /* ADCx_SC1n. */
    base->SC1[channelGroup] = ADC_SC1_ADCH(cmd->ConvChannelNum)
                            | (cmd->enInterruptOnCovnDone?ADC_SC1_AIEN_MASK:0U);
}

uint32_t ADC_HAL_GetChannelConvValue(ADC_Type *base, uint32_t channelGroup)
{
    return base->R[channelGroup];
}

bool     ADC_HAL_IsChannelConvDone(ADC_Type *base, uint32_t channelGroup)
{
    return ( ADC_SC1_COCO_MASK == (ADC_SC1_COCO_MASK & ADC_SC1_COCO_MASK) );
}

/* EOF. */
